
import Head from 'next/head'

<Head>
  <script>
    {
      `(function() {
         var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?e60fb290e204e04c5cb6f79b0ac1e697";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
       })();`
    }
  </script>
</Head>

![LangChain](https://pica.zhimg.com/50/v2-56e8bbb52aa271012541c1fe1ceb11a2_r.gif)





在文档中聊天，带有聊天记录
=============

本教程演示了如何使用`ConversationalRetrievalChain`设置聊天过程中带有聊天历史的链。与[RetrievalQAChain](vector_db_qa)唯一的区别是，这个链允许传入聊天历史，以便进行后续提问。

```python
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain.llms import OpenAI
from langchain.chains import ConversationalRetrievalChain

```

加载文档。您可以将其替换为您想要的任何类型的数据加载程序

```python
from langchain.document_loaders import TextLoader
loader = TextLoader("../../state_of_the_union.txt")
documents = loader.load()

```

如果您有多个加载程序需要组合，可以执行以下操作：

```python
# loaders = [....]
# docs = []
# for loader in loaders:
# docs.extend(loader.load())

```

现在我们将文档拆分、创建嵌入并将它们放入向量存储中。这使我们可以在它们之间进行语义搜索。

```python
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
documents = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(documents, embeddings)

```

```python
Using embedded DuckDB without persistence: data will be transient

```

现在我们可以创建一个内存对象，用于跟踪输入/输出并进行对话。

```python
from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

```

现在我们初始化`ConversationalRetrievalChain`

```python
qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), memory=memory)

```

```python
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query})

```

```python
result["answer"]

```

```python
" The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, and from a family of public school educators and police officers. He also said that she is a consensus builder and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans."

```

```python
query = "Did he mention who she suceeded"
result = qa({"question": query})

```

```python
result['answer']

```

```python
' Ketanji Brown Jackson succeeded Justice Stephen Breyer on the United States Supreme Court.'

```

传入聊天历史
------

在上面的示例中，我们使用Memory对象来跟踪聊天历史。我们也可以直接传递它。为此，我们需要初始化一个没有任何内存对象的链。

```python
qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever())

```

这里是一个没有聊天记录的提问示例

```python
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history})

```

```python
result["answer"]

```

```python
" The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, and from a family of public school educators and police officers. He also said that she is a consensus builder and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans."

```

这里是一个有一些聊天记录的提问示例

```python
chat_history = [(query, result["answer"])]
query = "Did he mention who she suceeded"
result = qa({"question": query, "chat_history": chat_history})

```

```python
result['answer']

```

```python
' Ketanji Brown Jackson succeeded Justice Stephen Breyer on the United States Supreme Court.'

```

返回源文件[#](#return-source-documents "标题的永久链接")
--------------------------------------------

您还可以轻松地从ConversationalRetrievalChain返回源文档。这对于您想要检查哪些文档被返回时非常有用。

```python
qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), return_source_documents=True)

```

```python
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history})

```

```python
result['source_documents'][0]

```

```python
Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections.   Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service.   One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court.   And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../state_of_the_union.txt'})

```

带有`search_distance`的ConversationalRetrievalChain[#](#conversationalretrievalchain-with-search-distance "标题的永久链接")
------------------------------------------------------------------------------------------------------------------

如果您正在使用支持按搜索距离过滤的向量存储，则可以添加阈值参数。

```python
vectordbkwargs = {"search_distance": 0.9}

```

```python
qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), return_source_documents=True)
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history, "vectordbkwargs": vectordbkwargs})

```

带有`map_reduce`的ConversationalRetrievalChain[#](#conversationalretrievalchain-with-map-reduce "标题的永久链接")
--------------------------------------------------------------------------------------------------------

我们还可以使用不同类型的组合文档链与ConversationalRetrievalChain链。

```python
from langchain.chains import LLMChain
from langchain.chains.question_answering import load_qa_chain
from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT

```

```python
llm = OpenAI(temperature=0)
question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)
doc_chain = load_qa_chain(llm, chain_type="map_reduce")

chain = ConversationalRetrievalChain(
    retriever=vectorstore.as_retriever(),
    question_generator=question_generator,
    combine_docs_chain=doc_chain,
)

```

```python
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = chain({"question": query, "chat_history": chat_history})

```

```python
result['answer']

```

```python
" The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, from a family of public school educators and police officers, a consensus builder, and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans."

```

带有源问题的ConversationalRetrievalChain问答[#](#conversationalretrievalchain-with-question-answering-with-sources "标题的永久链接")
---------------------------------------------------------------------------------------------------------------------

你也可以将这个链与带有来源的问答链一起使用。

```python
from langchain.chains.qa_with_sources import load_qa_with_sources_chain

```

```python
llm = OpenAI(temperature=0)
question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)
doc_chain = load_qa_with_sources_chain(llm, chain_type="map_reduce")

chain = ConversationalRetrievalChain(
    retriever=vectorstore.as_retriever(),
    question_generator=question_generator,
    combine_docs_chain=doc_chain,
)

```

```python
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = chain({"question": query, "chat_history": chat_history})

```

```python
result['answer']

```

```python
" The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, from a family of public school educators and police officers, a consensus builder, and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans. \nSOURCES: ../../state_of_the_union.txt"

```

ConversationalRetrievalChain 与流式输出到 `stdout`[#](#conversationalretrievalchain-with-streaming-to-stdout "这个标题的永久链接")
-------------------------------------------------------------------------------------------------------------------

在这个例子中，链的输出会被逐个 token 地流式输出到 `stdout`。

```python
from langchain.chains.llm import LLMChain
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
from langchain.chains.conversational_retrieval.prompts import CONDENSE_QUESTION_PROMPT, QA_PROMPT
from langchain.chains.question_answering import load_qa_chain

# Construct a ConversationalRetrievalChain with a streaming llm for combine docs
# and a separate, non-streaming llm for question generation
llm = OpenAI(temperature=0)
streaming_llm = OpenAI(streaming=True, callbacks=[StreamingStdOutCallbackHandler()], temperature=0)

question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)
doc_chain = load_qa_chain(streaming_llm, chain_type="stuff", prompt=QA_PROMPT)

qa = ConversationalRetrievalChain(
    retriever=vectorstore.as_retriever(), combine_docs_chain=doc_chain, question_generator=question_generator)

```

```python
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history})

```

```python
 The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, and from a family of public school educators and police officers. He also said that she is a consensus builder and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans.

```

```python
chat_history = [(query, result["answer"])]
query = "Did he mention who she suceeded"
result = qa({"question": query, "chat_history": chat_history})

```

```python
 Ketanji Brown Jackson succeeded Justice Stephen Breyer on the United States Supreme Court.

```

get_chat_history 函数[#](#get-chat-history-function "这个标题的永久链接")
----------------------------------------------------------------

你也可以指定一个 `get_chat_history` 函数，用于格式化聊天历史字符串。

```python
def get_chat_history(inputs) -> str:
    res = []
    for human, ai in inputs:
        res.append(f"Human:{human}\nAI:{ai}")
    return "\n".join(res)
qa = ConversationalRetrievalChain.from_llm(OpenAI(temperature=0), vectorstore.as_retriever(), get_chat_history=get_chat_history)

```

```python
chat_history = []
query = "What did the president say about Ketanji Brown Jackson"
result = qa({"question": query, "chat_history": chat_history})

```

```python
result['answer']

```

```python
" The president said that Ketanji Brown Jackson is one of the nation's top legal minds, a former top litigator in private practice, a former federal public defender, and from a family of public school educators and police officers. He also said that she is a consensus builder and has received a broad range of support from the Fraternal Order of Police to former judges appointed by Democrats and Republicans."

```

